/*
 * *
 * author:cgm
 * date:18-5-16 上午9:44
 * /
 */

package com.kaili.utils.Annotation;

import com.kaili.common.checkField.CheckFieldHandler;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * package name:com.kaili.utils.Annotation
 * author:hasee
 * date :2018/5/16
 * project:micro-service
 */
public class CheckFieldTools {
    public static final Class[] CLASS_TABLE = {Integer.class, int.class, Long.class, long.class, Boolean.class, boolean.class,
            Float.class, float.class, Double.class, double.class, String.class, BigDecimal.class, BigInteger.class,
            Date.class
    };

    public static Boolean checkField(Object obj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {
        Class cls = obj.getClass();
        /*Method[] methods = cls.getDeclaredMethods();
       for (int i = 0; i <methods.length ; i++) {
           System.out.println("method:"+methods[i].getName());
       }*/
        List<Field> fieldList = getAllField(cls);
        for (int i = 0; i < fieldList.size(); i++) {
            Field field = fieldList.get(i);
            CheckField checkField = field.getAnnotation(CheckField.class);
            if (checkField != null) {
                Object value;
                Class clz = field.getDeclaringClass();
                Method method = clz.getDeclaredMethod(getFieldGetFunction(field.getName()));
                value = method.invoke(obj);
                if (value == null) {
                    return false;
                }
                if (isInClassTable(field.getType())) {
                    String regExp = checkField.regexp();
                    String matchString;
                    if (!regExp.equals("")) {
                        matchString = "" + value;
                        Pattern pattern = Pattern.compile(regExp);
                        Matcher matcher = pattern.matcher(matchString);
                        if (!matcher.matches()) {
                            return false;
                        }
                    }
                    if (!checkField.checkHandlerClass().equals(Void.class)) {
                        Class cls2 = checkField.checkHandlerClass();
                        if (cls2 != null) {
                            Object object = cls2.newInstance();
                            if (object instanceof CheckFieldHandler) {
                                CheckFieldHandler handler = (CheckFieldHandler) object;
                                if (!handler.checkField(value)) {
                                    return false;
                                }
                            } else {
                                return false;
                            }
                        }
                    }
                } else if (field.getType().equals(List.class) || field.getType().equals(ArrayList.class)) {
                    List<Object> lists = (List<Object>) value;
                    for (int j = 0; j < lists.size(); j++) {
                        Object object = lists.get(i);
                        if (!checkField(value)) {
                            return false;
                        }
                    }
                } else {
                    if (!checkField(value)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public static List<Field> getAllField(Class cls) {
        List<Field> fields = new ArrayList<>();
        Field[] fs = cls.getDeclaredFields();
        for (int i = 0; i < fs.length; i++) {
            fields.add(fs[i]);
        }
        if (cls.getSuperclass() != null) {
            List<Field> fields1 = getAllField(cls.getSuperclass());
            fields.addAll(fields1);
        }
        return fields;
    }
    public static String getFieldGetFunction(String fieldName) {
        return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());
    }

    public static boolean isInClassTable(Class cls) {
        for (int i = 0; i < CLASS_TABLE.length; i++) {
            if (cls.equals(CLASS_TABLE[i])) {
                return true;
            }
        }
        return false;
    }
}
